﻿using Common;
using DataLibrary;
using ImageUploader;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace ImageUploaderServer
{
    public partial class Form_Control : Form
    {
        PublicMethod pm = new PublicMethod();
        Thread thListen = null;
        Thread thInsert = null;
        Thread thCheck = null;
        private ImageManagerEntities ime = new ImageManagerEntities();
        private Hashtable htArgs = new Hashtable();
        //private Hashtable htCheck = new Hashtable();//检测hash
        //private static Hashtable htIntercept = new Hashtable(1000);//记录一天的sn号，为了排重

        //private static Dictionary<string, DateTime> InterceptDic = new Dictionary<string, DateTime>(1000);//2层拦截，1000个号码为单位
        private static byte[] _buffer = new byte[102400];
        private static int _receiveCount = 0;
        //private static int _receiveTotal = 0;
        private static string _receiveString = string.Empty;
        private static Socket listenSocket = null;
        private static List<ImageInfo> iList = new List<ImageInfo>();
        private static Boolean tmpFlag = true;
        private static Boolean InsertFlag = false;
        //private static Boolean CheckFlag = false;
        private static string errSocketMsg;//发送错误信息到客户端
        private static string dir = System.Configuration.ConfigurationManager.AppSettings["FtpPath"] + "\\repeatLog";
        private static string repeatFile = "";
        public Form_Control()
        {
            InitializeComponent();
            txt_localIP.Text = pm.GetLocalIP();
            txt_localPort.Text = "50001";
            ListBox.CheckForIllegalCrossThreadCalls = false;//关闭跨线程对listbox的检查
            ReadDb();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            CheckServerAndDisk();
            DataTable dt = new DataTable();
            var servers = ime.ServerInfo;
            if (servers != null)
            {
                foreach (var server in servers)
                {
                    var serverdisk = server.ServerDisk;
                    if (serverdisk != null)
                    {
                        foreach (var disk in serverdisk)
                        {
                            dataGridView1.Rows.Add(disk.ServerInfo.ServerIP, disk.DiskInfo.DiskName, Math.Round((decimal)(disk.DiskInfo.DiskSize / 1024 / 1024), 2).ToString() + "M", Math.Round((decimal)(disk.DiskInfo.DiskFree / 1024 / 1024), 2).ToString() + "M", disk.DiskInfo.DiskLabel);
                        }
                    }
                }
            }
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            btn_Start.Enabled = false;
            btn_Close.Enabled = true;
            try
            {
                IPAddress ip = IPAddress.Parse(txt_localIP.Text);
                IPEndPoint ep = new IPEndPoint(ip, int.Parse(txt_localPort.Text));
                listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.Bind(ep);
                listenSocket.Listen(20);
                ShowMsg.showMsg(listb_InfoList, "清理FTP路径...");
                PublicMethod.DelectDir(System.Configuration.ConfigurationManager.AppSettings["FtpPath"].ToString());//清理FTP路径
                ShowMsg.showMsg(listb_InfoList, "清理FTP路径...ok!");
                ShowMsg.showMsg(listb_InfoList, "服务器开始监听...");
                thListen = new Thread(ListenClientConnect);//监听线程
                thListen.IsBackground = true;
                thListen.Start(listenSocket);
                InsertFlag = true;
                thInsert = new Thread(SleepToInsert, 2);//入库线程
                thInsert.IsBackground = true;
                thInsert.Start();
                thCheck = new Thread(SleepToCheckInsert);//验证线程
                thCheck.IsBackground = true;
                thCheck.Start();
            }
            catch (Exception ex)
            {
                ShowMsg.showMsg(listb_InfoList, ex.Message, 3);
            }
        }
        private void btn_Close_Click(object sender, EventArgs e)
        {
            if (listb_ClientList.Items.Count == 0)
            {
                DialogResult = MessageBox.Show("监听服务已启动，尚未有任何客户端接入，关闭监听会直接退出客户端，是否继续？", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
                if (DialogResult == DialogResult.Yes)
                {
                    this.Close();
                }
            }
            else
            {
                btn_Start.Enabled = true;
                btn_Close.Enabled = false;
                if (thListen != null)
                    thListen.Abort();
                if (listenSocket != null)
                {
                    listenSocket.Close();
                }
                if (thInsert != null)
                    thInsert.Abort();

                ShowMsg.showMsg(listb_InfoList, "监听结束");
            }
        }

        private void ToolMenu_ServerManage_Click(object sender, EventArgs e)
        {
            Form_ServerList f_s = new Form_ServerList();
            f_s.Show();
        }

        private void listb_InfoList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            int index = this.listb_InfoList.IndexFromPoint(e.X, e.Y);
            listb_InfoList.SelectedIndex = index;
            if (listb_InfoList.SelectedIndex != -1)
            {
                MessageBox.Show(listb_InfoList.SelectedItem.ToString());
            }
        }


        private void ListenClientConnect(object listenSocket)
        {
            Socket clientSocket = (Socket)listenSocket;
            while (true)
            {
                // 等待连接
                Socket transferSocket = clientSocket.Accept();
                Thread thread = new Thread(ReceiveData);
                thread.IsBackground = true;
                thread.Start(transferSocket);
            }
        }

        /// <summary>
        /// socket 接受图片信息，保存在临时路径
        /// </summary>
        /// <param name="transferSocket"></param>
        private void ReceiveData(object transferSocket)
        {
            if (!InsertFlag)
            {
                thInsert = new Thread(SleepToInsert, 2);
                thInsert.IsBackground = true;
                thInsert.Start();
            }
            Socket clientSocket = (Socket)transferSocket;
            ShowMsg.showMsg(listb_InfoList, "client " + clientSocket.RemoteEndPoint.ToString() + ": connect...");
            ShowMsg.showMsg(listb_ClientList, clientSocket.RemoteEndPoint.ToString());
            if (!string.IsNullOrEmpty(errSocketMsg))
            {
                clientSocket.SendTo(Encoding.UTF8.GetBytes(errSocketMsg), clientSocket.RemoteEndPoint);//将错误数据发送到客户端
                errSocketMsg = "";
                Thread.Sleep(100);
            }
            try
            {
                clientSocket.Send(Encoding.UTF8.GetBytes("yes"));//告诉客户端，我这准备完毕
                Thread.Sleep(100);
                while (true)
                {
                    string recMsg = ReceiveConsole(clientSocket);

                    if (recMsg.Contains("send ok"))
                    {
                        string[] parts = recMsg.Split('|');
                        string userNum = parts[0];
                        string oldPath = parts[1];
                        string newfile = parts[2];
                        string ftpPath = System.Configuration.ConfigurationManager.AppSettings["FtpPath"].ToString();
                        string fullPath = Path.Combine(ftpPath, Path.GetFileName(oldPath));//这里的tempFile既是一个临时目录，又是指定的ftp路径，不可修改；
                        string newPath = GetPath(newfile);
                        FileInfo fi = new FileInfo(fullPath);
                        fi.MoveTo(newPath);
                        double len = Math.Round((double)fi.Length / 1024, 2);
                        SaveToDb(userNum, newPath, newfile, len.ToString() + "Kb", oldPath);
                        //_receiveTotal = int.Parse(total);
                        ShowMsg.showMsg(listb_InfoList, newfile + " ok!");
                        //htCheck.Add(oldPath, newPath);
                        Thread.Sleep(100);
                        break;
                    }
                    else if (recMsg.Contains("check"))
                    {
                        ShowMsg.showMsg(listb_InfoList, "客户端发来的验证信息");
                        break;
                    }
                    else if(recMsg.Contains("start"))
                    {
                        ShowMsg.showMsg(listb_InfoList, "批量开始");
                        if(string.IsNullOrEmpty(repeatFile)){                            
                            string[] parts = recMsg.Split('|');
                            repeatFile = dir + "\\" + parts[1] + "_" + parts[2] + "_repeat.txt";
                        } 
                        if (File.Exists(repeatFile))
                            File.Delete(repeatFile);//先删掉上次的重复记录文件
                        break;
                    }
                    else if (string.IsNullOrEmpty(recMsg))
                    {
                        ShowMsg.showMsg(listb_InfoList, "socket数据延时，文件未能成功保存");
                        break;
                    }

                }
            }
            catch (Exception ex)
            {
                ShowMsg.showMsg(listb_InfoList, ex.StackTrace, 3);
                clientSocket.Close();
            }
            finally
            {
                ShowMsg.showMsg(listb_InfoList, "disconnect...");
                if (listb_InfoList.Items.Count > 1000)
                    listb_InfoList.Items.Clear();
            }
        }


        /// <summary>
        /// 选择存储路径
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        private string GetPath(string filename)
        {
            string final_path = string.Empty;
            string root_path = string.Empty;
            DiskInfo disk = new DiskInfo();
            ServerDisk sd = new ServerDisk();
            if (htArgs.ContainsKey("RootPath"))
            {
                root_path = htArgs["RootPath"].ToString();
            }
            else
            {
                disk = ime.DiskInfo.Where(u => u.Status == 0).OrderBy(u => u.DiskFree).First();//这里取剩余空间最小的那块硬盘，存满一块换一块，只为方便管理，不管IO负载，妹的可这一块干！
                sd = disk.ServerDisk.First();
                if (disk.DiskFree <= (decimal)1024 * 1024 * 1024 * 50)
                {
                    ShowMsg.showMsg(listb_InfoList, "硬盘空间不足，请及时更换，卷标为:" + disk.DiskLabel, 2);
                    Email.SendEmail("wtlemon@126.com", "硬盘不足", "服务器" + disk.ServerDisk.First().ServerInfo.ServerIP.ToString() + "上，卷标为:" + disk.DiskLabel + "的磁盘空间不足,剩余空间为：" + disk.DiskFree.ToString());
                    disk.Status = 1;
                    ime.SaveChanges();
                }
                root_path = disk.DiskName;
                htArgs.Add("RootPath", root_path);
                htArgs.Add("diskServerIP", sd.ServerInfo.ServerIP);
                htArgs.Add("DiskID", sd.DiskID);
            }
            string[] parts = filename.Split('-');
            string year = parts[5].Substring(0, 4);
            string date = parts[5].Substring(0, 8);
            //存储路径：盘符\\images\\（不）合格\\年\\日期\\车间\\班次\\机号
            string path = string.Format(@"{0}\Images\{1}\{2}\{3}\{4}\{5}\{6}", root_path, parts[1], year, date, parts[2], parts[3], parts[4]);
            
            if (htArgs["diskServerIP"].ToString() != txt_localIP.Text)
            {
                path = string.Format(@"\\{0}\{1}", disk.ServerDisk.First().ServerInfo.ServerIP, path.Replace(":", ""));
            }
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            final_path = Path.Combine(path, filename);
            return final_path;
        }

        /// <summary>
        /// 写入List，批量插入
        /// </summary>
        /// <param name="userNum">用户编号</param>
        /// <param name="imagePath"></param>
        /// <param name="qualityid"></param>
        /// <param name="imageName"></param>
        /// <param name="imageSize"></param>
        /// <param name="oriPath"></param>
        private void SaveToDb(string userNum, string imagePath, string imageName, string imageSize, string oriPath)
        {
            try
            {
                string[] parts = imageName.Split('-');
                string workshopName = parts[2];
                string teamName = parts[3];
                string machineNum = parts[4];
                Hashtable ht = new Hashtable();
                ht = (Hashtable)htArgs["workshops"];
                int workshopid = (int)ht[workshopName];
                ht = (Hashtable)htArgs["teams"];
                int teamid = (int)ht[teamName];
                ht = (Hashtable)htArgs["machines"];
                string mkey = workshopid.ToString() + "-" + machineNum;
                int machineid = (int)ht[mkey];
                string originPath = Path.GetFileNameWithoutExtension(oriPath);
                ImageInfo image = new ImageInfo();
                image.MachineID = machineid;
                image.ImageName = imageName;
                image.ImagePath = imagePath;
                image.TeamID = teamid;
                image.ImageSize = imageSize;
                image.OriginPath = originPath;
                image.QualityID = parts[1] == "合格" ? 1 : 2;
                image.Created_at = DateTime.Now;
                image.Updated_at = DateTime.Now;
                image.Transformed_at = DateTime.Now;
                image.DiskID = (int)htArgs["DiskID"];
                image.UserNum = userNum;
                iList.Add(image);
                if (!tmpFlag)
                {
                    try
                    {
                        thInsert = new Thread(SleepToInsert);
                        thInsert.IsBackground = true;
                        thInsert.Start();
                        tmpFlag = true;
                    }
                    catch
                    {
                        ShowMsg.showMsg(listb_InfoList, "数据服务重启失败");
                    }
                }
            }
            catch (Exception ex)
            {
                ShowMsg.showMsg(listb_InfoList, "插入列表时出错，信息：" + ex.Message + "，堆栈:" + ex.StackTrace);
            }
        }

        /// <summary>
        /// 批量插入
        /// </summary>        
        private void SleepToInsert(object _returnSocket)
        {
            try
            {
                DateTime dt = DateTime.Now;
                //int cnt = 0;
                while (true)
                {
                    Thread.Sleep(1000 * 20);
                    if (iList.Count() > 0)
                    {
                        ime.ImageInfo.AddRange(iList);
                        ime.SaveChanges();
                        ime.Entry(new ImageInfo()).State = System.Data.Entity.EntityState.Detached;
                        ShowMsg.showMsg(listb_InfoList, "DB:插入了" + iList.Count() + "条数据", 2);
                        iList.Clear();
                        //cnt = 0;
                    }
                    //else
                    //{
                    //    cnt++;
                    //    if (cnt % 10000 == 0)
                    //    {
                    //        InsertFlag = false;
                    //        ShowMsg.showMsg(listb_InfoList, "长时间未检测到客户端连接，DB服务即将关闭...");
                    //        Thread.Sleep(1000);
                    //        break;
                    //    }
                    //}
                }
            }
            catch (Exception ex)
            {
                ime.Dispose();
                ime = new ImageManagerEntities();
                if (ex.Message.Trim() == "An error occurred while updating the entries. See the inner exception for details.")
                {
                    errSocketMsg = "Data Repeat|";
                    RollBack();
                }
                else
                {
                    Email.SendEmail("wtlemon@126.com", "系统出错", ex.Message);
                    tmpFlag = false;
                    Thread.Sleep(100);                    
                }
                ShowMsg.showMsg(listb_InfoList, "清理FTP路径...", 3);
                PublicMethod.DelectDir(System.Configuration.ConfigurationManager.AppSettings["FtpPath"].ToString());//清理FTP路径
                ShowMsg.showMsg(listb_InfoList, "清理FTP路径...ok", 3);
                ShowMsg.showMsg(listb_InfoList, ex.Message, 3);
            }
        }

        /// <summary>
        /// 回滚操作，将重复的图片删掉，同时将一批进来的没有重复的数据入库。
        /// </summary>
        private void RollBack()
        {
            thInsert = new Thread(SleepToInsert, 2);
            thInsert.IsBackground = true;
            List<ImageInfo> notExistList = new List<ImageInfo>();
            List<string> tmpList = new List<string>();
            if (iList != null)
            {
                foreach (var item in iList)
                {
                    ImageInfo image = new ImageInfo();
                    image.MachineID = item.MachineID;
                    image.ImageName = item.ImageName;
                    image.ImagePath = item.ImagePath;
                    image.TeamID = item.TeamID;
                    image.ImageSize = item.ImageSize;
                    image.OriginPath = item.OriginPath;
                    image.QualityID = item.QualityID;
                    image.Created_at = DateTime.Now;
                    image.Updated_at = DateTime.Now;
                    image.Transformed_at = DateTime.Now;
                    image.DiskID = (int)htArgs["DiskID"];
                    image.UserNum = item.UserNum;
                    notExistList.Add(image);
                    tmpList.Add(item.OriginPath);
                }
                try
                {
                    var existList = ime.ImageInfo.AsQueryable().Where(u => tmpList.Contains(u.OriginPath)).ToList();

                    foreach (var item in existList)
                    {
                        var tmp = notExistList.Find(u => u.OriginPath == item.OriginPath);
                        if (tmp != null)
                        {
                            errSocketMsg += tmp.OriginPath + ";";
                            if (File.Exists(tmp.ImagePath))
                                File.Delete(tmp.ImagePath);//删掉重复的图片
                            notExistList.Remove(tmp);//删掉重复的数据列表项
                            string[] parts = tmp.ImageName.Split('-');
                            repeatFile = string.Format("{0}\\{1}_{2}_{3}_{4}_repeat.txt", dir, DateTime.Now.ToString("yyyyMMdd"), parts[2], parts[3], parts[4]);
                            WriteInfo(repeatFile, tmp.OriginPath);
                        }
                    }
                    ime.ImageInfo.AddRange(notExistList);
                    ime.SaveChanges();
                    ime.Entry(new ImageInfo()).State = System.Data.Entity.EntityState.Detached;
                    ShowMsg.showMsg(listb_InfoList, "DB：插入排重数据" + notExistList.Count + "条", 2);
                }
                catch (Exception ex)
                {
                    ShowMsg.showMsg(listb_InfoList, "排重后插入出错", 3);
                    Email.SendEmail("wtlemon@126.com", "数据重复", "排重后插入出错," + ex.Message + ",重复号码:" + errSocketMsg);
                    ime.Dispose();
                    ime = new ImageManagerEntities();
                }
                iList.Clear();
                thInsert.Start();
                Thread.Sleep(100);
            }
        }

        private void SleepToCheckInsert(object _returnSocket)
        {
            while (true)
            {
                Thread.Sleep(1000 * 60);
                if (RedisHelper.Get<List<string>>("checkBulk") != null)
                {
                    List<string> dropList = RedisHelper.Get<List<string>>("checkBulk");                    
                    //foreach (var item in dropList)
                    //{
                    //    ShowMsg.showMsg(listb_InfoList, "遗漏数据：" + item);
                    //    if (htCheck.Contains(item))
                    //    {
                    //        string filePath = htCheck[item].ToString();
                    //        string filename = Path.GetFileName(filePath);
                    //        string origin = item;
                    //        if (File.Exists(filePath))
                    //        {
                    //            SaveToDb("system", filePath, filename, "-", origin);
                    //            ShowMsg.showMsg(listb_InfoList, "插入遗漏数据：" + item);
                    //        }
                    //    }
                    //}                    
                    //htCheck.Clear();
                    RedisHelper.DelKey("checkBulk");

                }
                if(!tmpFlag)
                {
                    thInsert = new Thread(SleepToInsert,3);
                    thInsert.IsBackground = true;
                    thInsert.Start();
                    Email.SendEmail("wtlemon@126.com", "数据服务重启", "数据服务发生异常，已自动重启！");
                    tmpFlag = true;
                }
            }
        }

        public void ReadDb()
        {
            Hashtable htMachines = new Hashtable();
            var machines = ime.Machines.Select(u => new { u.MachineID, u.MachineNum, u.WorkshopID }).ToList();
            foreach (var machine in machines)
            {
                string mkey = machine.WorkshopID.ToString() + "-" + machine.MachineNum.ToString();
                htMachines.Add(mkey, machine.MachineID);//由于机器号和车间关联，所以这里把机器号和车间id的结合作为key，机器id作为value
            }
            Hashtable htWorkshops = new Hashtable();
            var workshops = ime.Workshops.Select(u => new { u.WorkshopID, u.Name }).ToList();
            foreach (var workshop in workshops)
            {
                htWorkshops.Add(workshop.Name, workshop.WorkshopID);//车间名称不可能重复，所以把名称当做key把id当做value
            }
            Hashtable htTeams = new Hashtable();
            var teams = ime.Teams.Select(u => new { u.TeamName, u.TeamID }).ToList();//班组名称也不能重复
            foreach (var team in teams)
            {
                htTeams.Add(team.TeamName, team.TeamID);
            }
            htArgs.Add("machines", htMachines);
            htArgs.Add("workshops", htWorkshops);
            htArgs.Add("teams", htTeams);
        }
                

        private string temp = string.Empty;
        private string ReceiveConsole(Socket socket)
        {
            _receiveCount = socket.Receive(_buffer);
            _receiveString = Encoding.UTF8.GetString(_buffer, 0, _receiveCount);
            if (string.IsNullOrEmpty(_receiveString))
            {
                ShowMsg.showMsg(listb_InfoList, "未接收到信息", 2);
            }
            else
            {
                ShowMsg.showMsg(listb_InfoList, "client : " + _receiveString);
            }
            return _receiveString;
        }


        //检查服务器和硬盘
        private void CheckServerAndDisk()
        {
            ShowMsg.showMsg(listb_InfoList, "正在检查服务器和硬盘挂载情况...");
            string IP = txt_localIP.Text;
            string Port = txt_localPort.Text;
            int ServerInfoID = 0;
            int DiskInfoID = 0;
            var _serverInfo = ime.ServerInfo.Where(u => u.ServerIP == IP && u.ServerPort == Port);
            if (_serverInfo.Count() == 0)
            {
                ServerInfo serverInfo = new ServerInfo();
                serverInfo.ServerIP = IP;
                serverInfo.ServerPort = Port;
                serverInfo.Created_at = DateTime.Now;
                serverInfo.Updated_at = DateTime.Now;
                ime.ServerInfo.Add(serverInfo);
                ime.SaveChanges();
                ServerInfoID = serverInfo.ServerID;
                ShowMsg.showMsg(listb_InfoList, "添加了1台服务器,IP:" + IP + ",Port:" + Port, 2);
            }
            else
                ServerInfoID = _serverInfo.First().ServerID;
            DriveInfo[] allDrives = DriveInfo.GetDrives();
            foreach (DriveInfo item in allDrives)
            {
                if (item.IsReady)
                {
                    if (!item.Name.ToUpper().Contains("C:")&&(item.DriveType == DriveType.Fixed || item.DriveType == DriveType.Removable))//是否需要判定磁盘类型
                    {
                        string volumeLabel = "";
                        if (string.IsNullOrEmpty(item.VolumeLabel))
                            volumeLabel = "本地磁盘:" + item.Name + "_" + DateTime.Now.ToString("yyyyMMdd");
                        else
                            volumeLabel = item.VolumeLabel;
                        int d = ime.DiskInfo.Where(u => u.DiskLabel == volumeLabel).Count();//先检查数据库中是否存在当前硬盘；
                        DiskInfo diskinfo = new DiskInfo();
                        diskinfo.DiskName = item.Name;
                        diskinfo.DiskLabel = volumeLabel;
                        diskinfo.DiskFree = item.TotalFreeSpace;
                        diskinfo.DiskSize = item.TotalSize;
                        diskinfo.Updated_at = DateTime.Now;
                        if (d == 0)
                        {
                            diskinfo.Created_at = DateTime.Now;
                            ime.DiskInfo.Add(diskinfo);
                            ime.SaveChanges();
                            ShowMsg.showMsg(listb_InfoList, "添加了1块硬盘,卷标:" + volumeLabel);
                            DiskInfoID = diskinfo.DiskID;
                            var serverDisk = new ServerDisk();
                            serverDisk.DiskID = DiskInfoID;
                            serverDisk.ServerID = ServerInfoID;
                            serverDisk.Created_at = DateTime.Now;
                            serverDisk.Updated_at = DateTime.Now;
                            ime.ServerDisk.Add(serverDisk);
                            ime.SaveChanges();
                        }
                        else
                        {
                            ime.SaveChanges();
                            ShowMsg.showMsg(listb_InfoList, "硬盘:" + volumeLabel + ",信息刷新完成");
                        }
                    }
                }
            }
            ShowMsg.showMsg(listb_InfoList, "硬盘挂载情况检查完成");
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            CheckServerAndDisk();
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="info">内容</param>
        private static void WriteInfo(string path, string info)
        {
            if (!File.Exists(path))
            {
                var myFile = File.Create(path);
                myFile.Close();
            }
            using (StreamWriter sw = File.AppendText(path))
            {
                sw.WriteLine(DateTime.Now + "-" + info);
            }
        }
    }
}
